package k8s

import (
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	"gitee.com/hexug/go-tools/common/validate"
	"gitee.com/hexug/go-tools/logger"
	appsv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	k8serrs "k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/json"
)

func (g *implK8s) CreateDeploymentFromYamlStr(c context.Context, req *CreateDeploymentFromYamlStrRequest) (dep *appsv1.Deployment, err error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("elapsed CreateDeploymentFromYamlStr: %v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, err
	}
	// 1. 参数校验
	if g.Clientset == nil {
		logger.L().Errorf("clientset不能为nil")
		return nil, errors.New("clientset不能为nil")
	}

	// 2. 解析YAML字符串为Deployment对象
	deployment, err := parseYAMLToDeployment(req.YamlStr)
	if err != nil {
		logger.L().Errorf("解析YAML失败: %v", err)
		return nil, fmt.Errorf("解析YAML失败: %w", err)
	}
	// 3. 获取Deployment对象
	reqGetDep := NewGetDeploymentRequest(deployment.Name)
	dep, err = g.GetDeployment(c, reqGetDep)
	if err == nil {
		logger.L().Infof("Deployment %s 已存在，不可重复创建", deployment.Name)
		return dep, fmt.Errorf("Deployment %s 已存在，不可重复创建", deployment.Name)
	}

	if g.Namespace != "" {
		deployment.Namespace = g.Namespace
	} else {
		// 3. 补充默认值（如果YAML中未指定）
		if deployment.Namespace == "" {
			deployment.Namespace = corev1.NamespaceDefault
		} else if g.Namespace != "" {
			deployment.Namespace = g.Namespace
		}
	}
	if deployment.Spec.Replicas == nil {
		defaultReplicas := int32(1)
		deployment.Spec.Replicas = &defaultReplicas
	}

	// 4. 设置上下文超时
	ctx, cancel := context.WithTimeout(c, 60*time.Second)
	defer cancel()

	// 5. 尝试创建Deployment
	dep, err = g.AppsV1().Deployments(deployment.Namespace).Create(
		ctx,
		deployment,
		metav1.CreateOptions{},
	)
	if err != nil {
		// 处理常见错误类型
		return handleCreateError(c, deployment, err)
	}
	return dep, nil
}

func (g *implK8s) DeleteDeployment(c context.Context, req *DeleteDeploymentRequest) (dep *appsv1.Deployment, err error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("%s elapsed K8SAPI_DeleteDeployment:%v", req.Name, time.Since(start))
	}()
	if err = validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, err
	}
	reqGetDep := NewGetDeploymentRequest(req.Name)
	dep, err = g.GetDeployment(c, reqGetDep)
	if err != nil {
		if k8serrs.IsNotFound(err) {
			logger.L().Infof("Deployment %s not found", req.Name)
			return nil, fmt.Errorf("Deployment %s not found", req.Name)
		}
		return nil, err
	}
	err = g.AppsV1().Deployments(g.Namespace).Delete(c, req.Name, metav1.DeleteOptions{})
	if err != nil {
		if k8serrs.IsNotFound(err) || k8serrs.IsGone(err) {
			logger.L().Infof("Deployment %s not found", req.Name)
			return nil, fmt.Errorf("Deployment %s not found", req.Name)
		}
		return nil, err
	}
	return dep, nil
}

func (g *implK8s) GetDeployment(c context.Context, req *GetDeploymentRequest) (*appsv1.Deployment, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("%s elapsed K8SAPI_GetDeployment:%v", req.Name, time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, err
	}
	return g.AppsV1().Deployments(g.Namespace).Get(c, req.Name, metav1.GetOptions{})
}

func (g *implK8s) ListDeployment(c context.Context, req *ListDeploymentRequest) (*appsv1.DeploymentList, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("elapsed K8SAPI_ListDeployment:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, err
	}
	listOp := metav1.ListOptions{}

	// 仅当labelmap非空时才设置标签选择器
	if req.LabelMap != nil && len(req.LabelMap) > 0 {
		labelSelector := metav1.LabelSelector{MatchLabels: req.LabelMap}
		listOp.LabelSelector = labels.Set(labelSelector.MatchLabels).String()
	}
	return g.AppsV1().Deployments(g.Namespace).List(c, listOp)
}

func (g *implK8s) PatchDeploymentFromJson(c context.Context, req *PatchDeploymentFromJsonRequest) (*appsv1.Deployment, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("%s elapsed K8SAPI_PatchDeploymentFromJson:%v", req.Name, time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, err
	}
	jsonData, err := json.Marshal(req.Data)
	if err != nil {
		logger.L().Errorf("Failed to marshal patch data: %v", err)
		return nil, fmt.Errorf("failed to marshal patch data: %v", err)
	}

	deployment, err := g.Clientset.AppsV1().Deployments(g.Namespace).Patch(c, req.Name, types.JSONPatchType, jsonData, metav1.PatchOptions{})
	if err != nil {
		logger.L().Errorf("Failed to patch deployment: %v", err)
		return nil, fmt.Errorf("failed to patch deployment: %v", err)
	}
	return deployment, nil
}

func (g *implK8s) PutDeploymentFromYaml(c context.Context, req *PutDeploymentFromYamlRequest) (*appsv1.Deployment, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("elapsed K8SAPI_PutDeploymentFromYaml:%v", time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, err
	}
	// 1. 参数校验
	if g.Clientset == nil {
		logger.L().Errorf("clientset不能为nil")
		return nil, errors.New("clientset不能为nil")
	}

	// 2. 解析YAML字符串为Deployment对象
	deployment, err := parseYAMLToDeployment(req.YamlStr)
	if err != nil {
		logger.L().Errorf("解析YAML失败: %v", err)
		return nil, fmt.Errorf("解析YAML失败: %w", err)
	}

	// 3. 获取Deployment对象
	reqGetDep := NewGetDeploymentRequest(deployment.Name)
	_, err = g.GetDeployment(c, reqGetDep)
	if err != nil {
		if k8serrs.IsNotFound(err) {
			logger.L().Infof("Deployment %s not found", deployment.Name)
			return nil, fmt.Errorf("Deployment %s not found", deployment.Name)
		}
		return nil, err
	}

	if g.Namespace != "" {
		deployment.Namespace = g.Namespace
	} else {
		// 4. 补充默认值（如果YAML中未指定）
		if deployment.Namespace == "" {
			deployment.Namespace = corev1.NamespaceDefault
		} else {
			deployment.Namespace = g.Namespace
		}
	}
	// 5. 设置上下文超时
	ctx, cancel := context.WithTimeout(c, 60*time.Second)
	defer cancel()

	// 6. 尝试创建Deployment
	deployment, err = g.AppsV1().Deployments(g.Namespace).Update(
		ctx,
		deployment,
		metav1.UpdateOptions{},
	)
	if err != nil {
		// 处理常见错误类型
		return handleCreateError(c, deployment, err)
	}
	return deployment, nil
}

func (g *implK8s) GetDeploymentPods(c context.Context, req *GetDeploymentPodsRequest) (*corev1.PodList, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("%s elapsed K8SAPI_GetDeploymentPods:%v", req.Name, time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, err
	}
	// 1. 先获取Deployment对象，提取其标签选择器
	deployment, err := g.AppsV1().Deployments(g.Namespace).Get(
		c,
		req.Name,
		metav1.GetOptions{},
	)
	if err != nil {
		return nil, fmt.Errorf("获取Deployment失败: %w", err)
	}

	// 2. 检查Deployment的选择器是否存在
	if deployment.Spec.Selector == nil {
		logger.L().Errorf("Deployment %s/%s 未定义选择器", g.Namespace, req.Name)
		return nil, fmt.Errorf("Deployment %s/%s 未定义选择器", g.Namespace, req.Name)
	}

	// 3. 将选择器转换为标签筛选字符串
	labelSelector := labels.Set(deployment.Spec.Selector.MatchLabels).String()

	// 4. 使用选择器筛选同一命名空间下的Pod
	pods, err := g.CoreV1().Pods(g.Namespace).List(
		c,
		metav1.ListOptions{
			LabelSelector: labelSelector,
		},
	)
	if err != nil {
		logger.L().Errorf("列出Pod失败: %v", err)
		return nil, fmt.Errorf("列出Pod失败: %w", err)
	}

	return pods, nil
}

func (g *implK8s) ExecCommandOnDeploymentPods(c context.Context, req *ExecCommandOnDeploymentPodsRequest) (map[string][]byte, map[string]error, error) {
	start := time.Now()
	defer func() {
		logger.L().Infof("%s elapsed K8SAPI_ExecCommandOnDeploymentPods:%v", req.DeploymentName, time.Since(start))
	}()
	if err := validate.V().Struct(req); err != nil {
		logger.L().Errorf("参数校验失败:%v", err)
		return nil, nil, err
	}
	if req.MaxConcurrency <= 0 {
		req.MaxConcurrency = 5 // 默认最大并发数为5
	}

	// 2. 复用 GetDeploymentPods 获取 Deployment 关联的所有 Pod
	podList, err := g.GetDeploymentPods(c, &GetDeploymentPodsRequest{
		Name: req.DeploymentName,
	})
	if err != nil {
		return nil, nil, fmt.Errorf("获取 Deployment 关联的 Pod 失败: %w", err)
	}
	if len(podList.Items) == 0 {
		return nil, nil, fmt.Errorf("Deployment %s 下未找到任何 Pod", req.DeploymentName)
	}

	// 3. 筛选运行中的 Pod（仅对运行状态的 Pod 执行命令）
	var targetPods []string
	for _, pod := range podList.Items {
		if pod.Status.Phase == corev1.PodRunning {
			targetPods = append(targetPods, pod.Name)
		} else {
			logger.L().Errorf("跳过非运行状态的 Pod %s（状态: %s）", pod.Name, pod.Status.Phase)
		}
	}
	if len(targetPods) == 0 {
		return nil, nil, fmt.Errorf("Deployment %s 下未找到运行中的 Pod", req.DeploymentName)
	}

	// 4. 并发执行命令（带最大并发控制）
	stdoutMap := make(map[string][]byte)
	stderrMap := make(map[string]error)
	var wg sync.WaitGroup
	semaphore := make(chan struct{}, req.MaxConcurrency) // 控制并发数
	mu := sync.Mutex{}                                   // 保护结果映射的并发写入

	for _, podName := range targetPods {
		wg.Add(1)
		go func(pod string) {
			defer wg.Done()
			semaphore <- struct{}{}        // 获取并发信号量
			defer func() { <-semaphore }() // 释放信号量

			// 为单个命令设置超时上下文（继承外部上下文的取消信号）
			cmdCtx, cancel := context.WithTimeout(c, req.CmdTimeout)
			defer cancel()
			req := NewExecInPodRequest(pod, req.Container, req.Command)
			// 调用已有的 ExecInPod 执行命令
			stdout, stderr, err := g.ExecInPod(cmdCtx, req)
			mu.Lock()
			defer mu.Unlock()

			if err != nil {
				// 聚合错误信息（包含 stderr 内容）
				errMsg := fmt.Sprintf("执行命令失败: %v", err)
				if len(stderr) > 0 {
					errMsg += fmt.Sprintf("，错误输出: %s", string(stderr))
				}
				stderrMap[pod] = errors.New(errMsg)
				logger.L().Errorf("Pod %s 执行命令出错: %v", pod, errMsg)
				return
			}

			// 记录成功结果
			stdoutMap[pod] = stdout
			logger.L().Infof("Pod %s 命令执行成功，输出长度: %d", pod, len(stdout))
		}(podName)
	}

	// 等待所有并发任务完成
	wg.Wait()

	return stdoutMap, stderrMap, nil
}
